#pragma once
#include <iostream>
#include <fstream>
#include <string>
#include <ctime>
#include <cstdarg>
#include <sys/types.h>
#include <unistd.h>
#include <pthread.h>
#include "LockGuard.hpp"

pthread_mutex_t _mutex = PTHREAD_MUTEX_INITIALIZER;
bool g_is_save = false;
// C99新特性
// LOG(DEBUG,"hello %d", 10) -> LogMessage(__FILE__,__LINE__,DEBUG,"hello %d", 10)
#define LOG(level, format, ...)                                                  \
    do                                                                           \
    {                                                                            \
        LogMessage(__FILE__, __LINE__, g_is_save, level, format, ##__VA_ARGS__); \
    } while (0)

// #define FUN() int a = 10, b = 100; \
// a *= 2; b *= 2; \
// std::cout << a + b << std::endl

// 1.日志等级
enum Level
{
    DEBUG = 0,
    INFO,
    WARNING,
    ERROR,
    FATAL
};

std::string LevelToString(int level)
{
    switch (level)
    {
    case DEBUG:
        return "Debug";
    case INFO:
        return "Info";
    case WARNING:
        return "Warning";
    case ERROR:
        return "Error";
    case FATAL:
        return "Fatal";
    default:
        return "Unkown";
    }
}

std::string TimeToString()
{
    time_t tm = time(nullptr);
    struct tm *format_time = localtime(&tm);
    char buffer[1024];
    snprintf(buffer, sizeof(buffer), "%d-%d-%d %d:%d:%d", format_time->tm_year + 1900, format_time->tm_mon + 1, format_time->tm_mday, format_time->tm_hour, format_time->tm_min, format_time->tm_sec);
    return buffer;
}

const std::string logfilename = "log.txt";
void SaveFile(std::string file, std::string buffer)
{
    std::ofstream out(file, std::ios::app); // 追加方式打开文件
    if (!out.is_open())
    {
        return;
    }
    out << buffer;
}
// 2.日志格式
// 日志等级 ：时间 ：日志所在文件 ：行数：日志内容
void LogMessage(std::string filename, int line, bool is_save, int level, const char *format, ...)
{
    std::string levelstr = LevelToString(level);
    std::string timestr = TimeToString();
    std::string pidstr = std::to_string(getgid());

    // 获取日志内容
    char buffer[1024];
    va_list arg;                                    // void* arg;
    va_start(arg, format);                          // arg = &format + sizeof(format); arg指向第一个可变参数
    vsnprintf(buffer, sizeof(buffer), format, arg); // 用arg指向的可变参数部分填充format字符串，并将结果输出到buffer中
    va_end(arg);                                    // arg = nullptr

    std::string ret = "[" + timestr + "]" + "[" + levelstr + "]" + "[pid:" + pidstr + "]" + "[" + filename + "]" + "[" + std::to_string(line) + "]" + buffer + "\n";

    // 保护显示器公共资源
    LockGuard lockguard(_mutex);
    if (is_save)
    {
        SaveFile(logfilename, ret);
    }
    else
    {
        std::cout << ret;
    }
}

#define EnableScreen()     \
    do                     \
    {                      \
        g_is_save = false; \
    } while (0)
#define EnableFile()      \
    do                    \
    {                     \
        g_is_save = true; \
    } while (0)
void Test(int num, ...)
{
    va_list arg;
    va_start(arg, num);
    while (num--)
    {
        int data = va_arg(arg, int); // data = *(int*)arg, arg += sizeof(int)
        std::cout << data << " ";
    }
    std::cout << std::endl;
    va_end(arg);
}